#pragma once
#include <string>

/************************************************************************/
/* 内存缓冲区操作类                                              */
/* author 王强                                             */
/************************************************************************/
template<typename T>
class MemoryOperator
{
public:
	/*
	 申请内存大小架构方法
	*/
	MemoryOperator(size_t initMem = 1024, size_t maxMem = 0xffffffff);

	/*
	 缓冲区架构方法
	*/
	MemoryOperator(void * buffer, size_t length);

	~MemoryOperator();

	/*
	  写入内存缓冲区
	  NO.1 写入内容
	  NO.2 写入多少
	*/
	size_t write(const T *buffer, size_t sizeNumner);

	size_t read( T *buffer, size_t sizeNumner);

	T * getBuffer();

	/*是否到了尾部最后4个字符是否是\r\n*/
	
	inline bool isEnd();

	// 释放缓冲区 重置
	// NO.1 是否释放缓冲区
	void trunc(bool isFreeBuff = true);

	// 获取文件长度
	inline size_t fSize();

private:
	// 缓冲区
	T * buffer;

	// 缓冲区长度
	size_t bufferLenth;

	// 写入位置
	size_t writePos;

	// 读取位置
	size_t readPos;

	// 缓冲区长度最大字节数
	size_t maxSize;

	// 缓冲区长度初始化字节数大小
	size_t initMemSize;

	// 是否是 自同构
	bool selfAlloc;

	// 文件 大小
	size_t fileSize;

	//禁止复制 拷贝
	MemoryOperator(const MemoryOperator &);

	MemoryOperator & operator = (const MemoryOperator &);

	// 剩余空间
	size_t surplusSpace();

	/* 
	   储备缓冲区 
	   NO.1 缓冲区大小
	*/
	size_t reserveSpace(size_t reserveNumber);
};

template<typename T>
bool MemoryOperator<T>::isEnd()
{
	if (this->fileSize < 4)
	{
		return false;
	}

	return this->buffer[this->fileSize - 2] == '\r' && this->buffer[this->fileSize - 1] == '\n';
}

template<typename T>
inline void MemoryOperator<T>::trunc(bool isFreeBuff)
{
	if (isFreeBuff && this->selfAlloc && this->buffer)
	{
		delete[] this->buffer;

		this->buffer = NULL;
	}

	this->writePos = 0;

	this->readPos = 0;

	this->fileSize = 0;
}

template<typename T>
inline size_t MemoryOperator<T>::fSize()
{
	return this->fileSize;
}

template<typename T>
MemoryOperator<T>::MemoryOperator(size_t initMem, size_t maxMem) :buffer(NULL),
	writePos(0),
	readPos(0),
	bufferLenth(0),
	selfAlloc(true),
	fileSize(0)
{
	assert(initMem <= maxMem);

	this->initMemSize = initMem;

	this->maxSize = maxMem;
}
template<typename T>
MemoryOperator<T>::MemoryOperator(void * buffer, size_t length) :writePos(0),
	readPos(0),
	maxSize(0),
	initMemSize(0),
	selfAlloc(false),
	fileSize(0)
{
	this->buffer = reinterpret_cast<char*>(buffer);

	this->bufferLenth = length;
}

template<typename T>
MemoryOperator<T>::~MemoryOperator()
{
	delete[] this->buffer;

	this->buffer = NULL;
}

template<typename T>
size_t MemoryOperator<T>::write(const T *buffer, size_t sizeNumner)
{
	size_t surplusNumber = this->reserveSpace(sizeNumner);

	if (surplusNumber <= 0)
	{
		return surplusNumber;
	}

	// 在缓冲区尾部复制
	memcpy(this->buffer + this->writePos, buffer, sizeNumner);

	this->writePos += sizeNumner;

	if (this->writePos > this->fileSize)
	{
		this->fileSize = this->writePos;
	}

	return sizeNumner;
}

template<typename T>
inline size_t MemoryOperator<T>::read( T * buffer, size_t sizeNumner)
{
	size_t realLength = this->fileSize - this->readPos;

	if (realLength > sizeNumner)
	{
		realLength = sizeNumner;
	}

	if (buffer == NULL || realLength < 0)
	{
		return 0;
	}
	
	memcpy(buffer, this->buffer + this->readPos, realLength);

	this->readPos += realLength;

	return realLength;
}

template<typename T>
T *  MemoryOperator<T>::getBuffer()
{
	return this->buffer;
}


template<typename T>
size_t  MemoryOperator<T>::surplusSpace()
{
	return this->bufferLenth - this->writePos;
}

template<typename T>
size_t  MemoryOperator<T>::reserveSpace(size_t reserveNumber)
{
	size_t length = this->surplusSpace();

	if (length > reserveNumber)
	{
		// 缓冲区足够
		return reserveNumber;
	}

	if (!this->selfAlloc)
	{
		// 重新分配空间
		return length;
	}

	// 申请的空间大于剩余的空间 比如 申请了350 ，只剩下300 还要判断最小申请内存，比如最小申请长度是100
	// 最少分配初始化大小的内存
	size_t leastDistributionMem = reserveNumber - length;

	if (leastDistributionMem < this->initMemSize)
	{
		leastDistributionMem = this->initMemSize;
	}

	size_t newSize = this->bufferLenth + leastDistributionMem;

	//检查内存申请是否越界
	if (newSize > this->maxSize)
	{
		newSize = this->maxSize;
	}

	// 新开辟的缓冲区 小于 原先的缓冲区长度
	if (newSize <= this->bufferLenth)
	{
		return this->surplusSpace();
	}

	T *temp = new T[newSize];

	memset(temp, 0, newSize);

	if (this->buffer)
	{
		memcpy(temp, this->buffer, this->bufferLenth);

		delete this->buffer;
	}

	this->buffer = temp;

	this->bufferLenth = newSize;

	return length < this->surplusSpace() ? this->surplusSpace() : length;
}

